<template>
  <div class="cj-infiniteloading" ref="scroller" @touchstart="touchStartHandle($event)" @touchmove="touchMoveHandle($event)">
    <template v-if="usePullDown">
      <div class="top-tips" v-if="isShowPullDownTips && isPullDownLoading">
        <i class="loading-hint"></i><span class="loading-txt">加载中...</span>
      </div>
    </template>
    <slot></slot>
    <div class="load-more">
      <div class="bottom-tips" v-if="isShowBottomTips">
        <template v-if="isLoading"> <i class="loading-hint"></i><span class="loading-txt">加载中...</span> </template>
        <span v-else-if="!hasMore && unloadMoreTxt" class="tips-txt">{{ unloadMoreTxt }}</span>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  name: 'cj-infiniteloading',
  props: {
    usePullDown: {
      type: Boolean,
      default: false,
    },
    isShowPullDownTips: {
      type: Boolean,
      default: true,
    },
    isPullDownHasMore:{
      type: Boolean,
      default: true,
    },
    isPullDownLoading: {
      type: Boolean,
      default: false,
    },
    pullDownThreshold:{
      type: Number,
      default: 200,
    },
    hasMore: {
      type: Boolean,
      default: true,
    },
    isLoading: {
      type: Boolean,
      default: false,
    },
    threshold: {
      type: Number,
      default: 200,
    },
    useWindow: {
      type: Boolean,
      default: true,
    },
    useCapture: {
      type: Boolean,
      default: false,
    },
    isShowMod: {
      type: Boolean,
      default: false,
    },
    isShowBottomTips: {
      type: Boolean,
      default: true,
    },
    unloadMoreTxt: {
      type: String,
      default: '哎呀，这里是底部了啦',
    },
    scrollChange: {
      type: Function,
    },
    containerId: {
      type: String,
      default: '',
    },
  },
  data() {
    return {
      startX: 0,
      startY: 0,
      diffX: 0,
      diffY: 0,
      beforeScrollTop: 0,
    };
  },

  mounted: function () {
    const parentElement = this.getParentElement(this.$el);
    let scrollEl = window;
    if (this.useWindow === false) {
      scrollEl = parentElement;
    }
    this.scrollEl = scrollEl;
    this.scrollListener();
  },

  methods: {
    touchStartHandle(e) {
      try {
        this.startX = Number(e.changedTouches[0].pageX);
        this.startY = Number(e.changedTouches[0].pageY);
      } catch (e) {
        console.log(e.message);
      }
    },
    touchMoveHandle(e) {
      let endX = Number(e.changedTouches[0].pageX);
      let endY = Number(e.changedTouches[0].pageY);
      this.diffX = endX - this.startX;
      this.diffY = endY - this.startY;
      this.$emit("touchMove")
    },
    getParentElement(el) {
      if (this.containerId) {
        return document.querySelector(`#${this.containerId}`);
      }
      return el && el.parentNode;
    },
    scrollListener() {
      this.scrollEl.addEventListener('scroll', this.handleScroll, this.useCapture);
      window.addEventListener('resize', this.handleScroll, this.useCapture);
    },

    requestAniFrame() {
      return (
        window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        function (callback) {
          window.setTimeout(callback, 1000 / 60);
        }
      );
    },

    handleScroll() {
      this.requestAniFrame()(() => {
        if (this.isScrollAtTop() && this.isPullDownHasMore && !this.isPullDownLoading && this.usePullDown) {
          this.$emit('loadPrev', this.scrollEl);
        }
        if (!this.isScrollAtBottom() || !this.hasMore || this.isLoading || !this.isShowMod) {
          return false;
        } else {
          this.$emit('loadmore');
        }

      });
    },

    calculateTopPosition(el) {
      if (!el) {
        return 0;
      }
      return el.offsetTop + this.calculateTopPosition(el.offsetParent);
    },

    getWindowScrollTop() {
      return window.pageYOffset !== undefined
        ? window.pageYOffset
        : (document.documentElement || document.body.parentNode || document.body).scrollTop;
    },
    isScrollAtTop() {
      let isScrollTop = false;
      let scrollTop = this.getWindowScrollTop();
      if (this.useWindow) {
        isScrollTop = scrollTop - this.pullDownThreshold <= 0 ? true : false
      } else {
        const { scrollHeight, clientHeight, scrollTop } = this.scrollEl;
        if (scrollTop <= 0) {
          if (clientHeight >= scrollHeight) {
            isScrollTop = false;
          } else if (scrollTop == 0) {
            isScrollTop = true;
          }
        } else {
          isScrollTop = scrollTop < this.pullDownThreshold ? true : false;
        }
      }
      return isScrollTop;
    },
    isScrollAtBottom() {
      let offsetDistance;

      let resScrollTop = 0;

      const windowScrollTop = this.getWindowScrollTop();

      if (this.useWindow) {
        offsetDistance = this.calculateTopPosition(this.$refs.scroller) + this.$refs.scroller.offsetHeight - windowScrollTop - window.innerHeight;
      } else {
        const { scrollHeight, clientHeight, scrollTop } = this.scrollEl;

        offsetDistance = scrollHeight - clientHeight - scrollTop;
        resScrollTop = scrollTop;
      }
      this.$emit('scrollChange', this.useWindow ? windowScrollTop : resScrollTop);
      // 保证是往下滑动的
      this.beforeScrollTop = windowScrollTop;
      return offsetDistance <= this.threshold && windowScrollTop >= this.beforeScrollTop;
    },
  },

  activated() {
    if (this.keepAlive) {
      this.keepAlive = false;
      this.scrollListener();
    }
  },

  deactivated() {
    this.keepAlive = true;
    this.scrollEl.removeEventListener('scroll', this.handleScroll, this.useCapture);
    window.removeEventListener('resize', this.handleScroll, this.useCapture);
  },

  destroyed() {
    this.scrollEl.removeEventListener('scroll', this.handleScroll, this.useCapture);
    window.removeEventListener('resize', this.handleScroll, this.useCapture);
  },
};
</script>
